package rc.db;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

import com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException;

public class BankDBRCAware extends BankDB
{
	public BankDBRCAware(List<Integer> balances, String url, String user,
			String password)
	{
		super(balances, url, user, password);
	}

	@Override
	public void transfer(int from, int to, int amount)
	{
		Connection conn = null;
		int tries = 0;
		boolean done = false;

		try {
			conn = DriverManager.getConnection(url, user, password);
			conn.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);

			while (!done && tries < 3) {
				++tries;

				try {
					int fromBalance, toBalance;
					PreparedStatement prep;
					ResultSet rs;

					conn.setAutoCommit(false);

					prep = conn
							.prepareStatement("SELECT money FROM accounts WHERE id = ?");

					prep.setInt(1, from);
					rs = prep.executeQuery();
					rs.next();
					fromBalance = rs.getInt(1);
					rs.close();

					prep.setInt(1, to);
					rs = prep.executeQuery();
					rs.next();
					toBalance = rs.getInt(1);
					rs.close();

					prep.close();

					try {
						// simulate some heavy calculations
						Thread.sleep(1000 + (int) Math.random() * 1000);
					} catch (InterruptedException e) {
					}

					prep = conn
							.prepareStatement("UPDATE accounts SET money = ? WHERE id = ?");

					prep.setInt(1, fromBalance - amount);
					prep.setInt(2, from);
					prep.executeUpdate();

					prep.setInt(1, toBalance + amount);
					prep.setInt(2, to);
					prep.executeUpdate();

					prep.close();

					conn.commit();
					done = true;
				} catch (MySQLTransactionRollbackException e) {
					conn.rollback();
				}
			}
		} catch (Exception e) {
			if (conn != null) {
				try {
					conn.rollback();
				} catch (SQLException e1) {
				}
			}

			throw new RuntimeException(e);
		} finally {
			if (conn != null) {
				try {
					conn.close();
				} catch (SQLException e) {
				}
			}
		}
	}
}
